package org.erp.procurement.service;

import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.erp.procurement.enums.OrderEventEnum;
import org.erp.procurement.enums.OrderStatusEnum;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;

/**
 * 订单状态机服务转换层
 *
 * @author libin
 * @version 1.0
 * @description: 订单状态机服务转换层
 * @date 2025/11/10 1:33
 **/
@Log4j2
@Service
@AllArgsConstructor
public class OrderStateMachineService {

    private final StateMachineFactory<OrderStatusEnum, OrderEventEnum> orderStateMachineFactory;

    private final StateMachinePersister<OrderStatusEnum, OrderEventEnum, String> stateMachinePersister;

    @SneakyThrows
    public boolean process(String orderNo, OrderEventEnum orderEventEnum) {
        StateMachine<OrderStatusEnum, OrderEventEnum> stateMachine = orderStateMachineFactory.getStateMachine(orderNo);
        //从数据库恢复状态
        stateMachine.start();
        stateMachinePersister.restore(stateMachine, orderNo);
        stateMachine.addStateListener(new StateMachineListenerAdapter<>() {
            @Override
            public void eventNotAccepted(Message<OrderEventEnum> event) {
                log.error("订单号 {} 状态机事件拒绝: {}", orderNo, event.getPayload().getMessage());
            }
        });
        //构建事件消息
        Message<OrderEventEnum> message = MessageBuilder.withPayload(orderEventEnum)
                .setHeader("orderNo", orderNo).build();
        //执行状态流转
        boolean result = stateMachine.sendEvent(message);
        if (!result) {
            log.error("订单号 {} 状态机事件拒绝: {}", orderNo, orderEventEnum.getMessage());
        }
        //持久化数据库
        try {
            stateMachinePersister.persist(stateMachine, orderNo);
        }finally {
            stateMachine.stop();
        }
        return result;
    }
}
